/*
 * Copyright 2007 Rob Nielsen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.proxymatic.apps.merger;

import com.googlecode.proxymatic.core.AbstractProxyApplication;
import com.googlecode.proxymatic.core.HandlerConfiguration;
import com.googlecode.proxymatic.core.handlers.method.SameInterfaceMethodHandler;
import com.googlecode.proxymatic.core.util.ReflectUtil;

public class ProxyObjectMerger extends AbstractProxyApplication implements ObjectMerger {
    protected void setUpHandlerConfiguration(HandlerConfiguration handlerConfiguration) {
        handlerConfiguration.addHandler(new SameInterfaceMethodHandler());
    }

    protected String getProxyType() {
        return "ObjectMerger";
    }

    /**
     * Merges a number of objects into a single object implementing all interfaces of the individual objects. If the
     * same method is implemented by multiple objects, the first in the array will be called when the returned object is
     * called.
     *
     * @param implementations the objects to merge
     * @return a merged object
     */
    public Object merge(Object[] implementations) {
        Class[] interfaces = ReflectUtil.createInterfaceArray(implementations);
        return create(proxy().implementingInterfaces(interfaces).withImplementationObjects(implementations));
    }

    /**
     * Merges a number of objects into a single object implementing an master interface.  This should be an interface
     * that extends all the required interfaces of the implementation objects.  If no suitable interfaces exist on the
     * implementation objects, DynamicInterfacer.aggregate() method can be used instead.
     *
     * @param targetInterface the desired destination interface
     * @param implementations the objects to merge
     * @return a merged object
     */
    public <T> T merge(Class<T> targetInterface, Object[] implementations) {
        return targetInterface.cast(create(proxy()
                .implementingInterface(targetInterface)
                .withImplementationObjects(implementations)));
    }
}
